#ifndef _CCB_CCBREADER_H_
#define _CCB_CCBREADER_H_

#include "cocos2d.h"
#include "ExtensionMacros.h"
#include <string>
#include <vector>
#include "CCBSequence.h"


#define CCB_STATIC_NEW_AUTORELEASE_OBJECT_METHOD(T, METHOD) static T * METHOD() { \
    T * ptr = new T(); \
    if(ptr != NULL) { \
        ptr->autorelease(); \
        return ptr; \
    } \
    CC_SAFE_DELETE(ptr); \
    return NULL; \
}

#define CCB_STATIC_NEW_AUTORELEASE_OBJECT_WITH_INIT_METHOD(T, METHOD) static T * METHOD() { \
    T * ptr = new T(); \
    if(ptr != NULL && ptr->init()) { \
        ptr->autorelease(); \
        return ptr; \
    } \
    CC_SAFE_DELETE(ptr); \
    return NULL; \
}

#define CCB_VERSION 5

NS_CC_EXT_BEGIN

/**
 * @addtogroup cocosbuilder
 * @{
 */

class CCBFile : public Node
{
private:
    Node *_CCBFileNode;
    
public:
    CCBFile();
    
    static CCBFile* create();
    
    Node* getCCBFileNode();
    void setCCBFileNode(Node *pNode); // retain
};

/* Forward declaration. */
class NodeLoader;
class NodeLoaderLibrary;
class NodeLoaderListener;
class CCBMemberVariableAssigner;
class CCBSelectorResolver;
class CCBAnimationManager;
class CCBKeyframe;

/**
 * @brief Parse CCBI file which is generated by CocosBuilder
 */
class CCBReader : public Object 
{
public:
    enum class PropertyType {
        POSITION = 0,
        SIZE,
        POINT,
        POINT_LOCK,
        SCALE_LOCK,
        DEGREES,
        INTEGER,
        FLOAT,
        FLOAT_VAR,
        CHECK,
        SPRITEFRAME,
        TEXTURE,
        BYTE,
        COLOR3,
        COLOR4F_VAR,
        FLIP,
        BLEND_MODE,
        FNT_FILE,
        TEXT,
        FONT_TTF,
        INTEGER_LABELED,
        BLOCK,
        ANIMATION,
        CCB_FILE,
        STRING,
        BLOCK_CONTROL,
        FLOAT_SCALE,
        FLOAT_XY
    };
    
    enum class FloatType {
        _0 = 0,
        _1,
        MINUS1,
        _05,
        INTEGER,
        FULL
    };
    
    enum class PlatformType {
        ALL = 0,
        IOS,
        MAC
    };
    
    enum class TargetType {
        NONE = 0,
        DOCUMENT_ROOT = 1,
        OWNER = 2,
    };
    
    enum class PositionType
    {
        RELATIVE_BOTTOM_LEFT,
        RELATIVE_TOP_LEFT,
        RELATIVE_TOP_RIGHT,
        RELATIVE_BOTTOM_RIGHT,
        PERCENT,
        MULTIPLY_RESOLUTION,
    };
    
    enum class SizeType
    {
        ABSOLUTE,
        PERCENT,
        RELATIVE_CONTAINER,
        HORIZONTAL_PERCENT,
        VERTICAL_PERCENT,
        MULTIPLY_RESOLUTION,
    };
    
    enum class ScaleType
    {
        ABSOLUTE,
        MULTIPLY_RESOLUTION
    };
    
    CCBReader(NodeLoaderLibrary *pNodeLoaderLibrary, CCBMemberVariableAssigner *pCCBMemberVariableAssigner = NULL, CCBSelectorResolver *pCCBSelectorResolver = NULL, NodeLoaderListener *pNodeLoaderListener = NULL);
    CCBReader(CCBReader *ccbReader);
    virtual ~CCBReader();
    CCBReader();
   
    void setCCBRootPath(const char* ccbRootPath);
    const std::string& getCCBRootPath() const;

    Node* readNodeGraphFromFile(const char *pCCBFileName);
    Node* readNodeGraphFromFile(const char *pCCBFileName, Object *pOwner);
    Node* readNodeGraphFromFile(const char *pCCBFileName, Object *pOwner, const Size &parentSize);
    
    Node* readNodeGraphFromData(Data *pData, Object *pOwner, const Size &parentSize);
   
    Scene* createSceneWithNodeGraphFromFile(const char *pCCBFileName);
    Scene* createSceneWithNodeGraphFromFile(const char *pCCBFileName, Object *pOwner);
    Scene* createSceneWithNodeGraphFromFile(const char *pCCBFileName, Object *pOwner, const Size &parentSize);

    CCBMemberVariableAssigner* getCCBMemberVariableAssigner();
    CCBSelectorResolver* getCCBSelectorResolver();
    
    CCBAnimationManager* getAnimationManager();
    void setAnimationManager(CCBAnimationManager *pAnimationManager);
    
    // Used in NodeLoader::parseProperties()
    std::set<std::string>* getAnimatedProperties();
    std::set<std::string>& getLoadedSpriteSheet();
    Object* getOwner();

    /* Utility methods. */
    static std::string lastPathComponent(const char* pString);
    static std::string deletePathExtension(const char* pString);
    static std::string toLowerCase(const char* pString);
    static bool endsWith(const char* pString, const char* pEnding);

    /* Parse methods. */
    int readInt(bool pSigned);
    unsigned char readByte();
    bool readBool();
    std::string readUTF8();
    float readFloat();
    std::string readCachedString();
    bool isJSControlled();
            
    
    bool readCallbackKeyframesForSeq(CCBSequence* seq);
    bool readSoundKeyframesForSeq(CCBSequence* seq);


    
    Array* getOwnerCallbackNames();
    Array* getOwnerCallbackNodes();
    Array* getOwnerOutletNames();
    Array* getOwnerOutletNodes();
    Array* getNodesWithAnimationManagers();
    Array* getAnimationManagersForNodes();

    Dictionary* getAnimationManagers();
    void setAnimationManagers(Dictionary* x);  // weak reference
    
    void addOwnerCallbackName(std::string name);
    void addOwnerCallbackNode(Node *node);
    
    void addDocumentCallbackName(std::string name);
    void addDocumentCallbackNode(Node *node);
    
    static float getResolutionScale();
    static void setResolutionScale(float scale);
    
    Node* readFileWithCleanUp(bool bCleanUp, Dictionary* am);
    
    void addOwnerOutletName(std::string name);
    void addOwnerOutletNode(Node *node);

private:
    void cleanUpNodeGraph(Node *pNode);
    bool readSequences();
    CCBKeyframe* readKeyframe(PropertyType type);
    
    bool readHeader();
    bool readStringCache();
    //void readStringCacheEntry();
    Node* readNodeGraph();
    Node* readNodeGraph(Node * pParent);

    bool getBit();
    void alignBits();

    friend class NodeLoader;

private:
    Data *_data;
    unsigned char *_bytes;
    int _currentByte;
    int _currentBit;
    
    std::vector<std::string> _stringCache;
    std::set<std::string> _loadedSpriteSheets;
    
    Object *_owner;
    
    CCBAnimationManager *_actionManager; //retain
    Dictionary* _actionManagers;
    
    std::set<std::string> *_animatedProps;
    
    NodeLoaderLibrary *_nodeLoaderLibrary;
    NodeLoaderListener *_nodeLoaderListener;
    CCBMemberVariableAssigner *_CCBMemberVariableAssigner;
    CCBSelectorResolver *_CCBSelectorResolver;
    
    std::vector<std::string> _ownerOutletNames;
    Array* _ownerOutletNodes;
    Array* _nodesWithAnimationManagers;
    Array* _animationManagersForNodes;
    
    std::vector<std::string> _ownerCallbackNames;
    Array* _ownerCallbackNodes;
    std::string _CCBRootPath;
    
    bool _jsControlled;
    
    bool _hasScriptingOwner;
    bool init();
};

// end of effects group
/// @}

NS_CC_EXT_END

#endif
